//      stl_helper.h
//      
//      Copyright 2012 tqlong <tqlong@espada>
//      
//      This program is free software; you can redistribute it and/or modify
//      it under the terms of the GNU General Public License as published by
//      the Free Software Foundation; either version 2 of the License, or
//      (at your option) any later version.
//      
//      This program is distributed in the hope that it will be useful,
//      but WITHOUT ANY WARRANTY; without even the implied warranty of
//      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//      GNU General Public License for more details.
//      
//      You should have received a copy of the GNU General Public License
//      along with this program; if not, write to the Free Software
//      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
//      MA 02110-1301, USA.

#ifndef STL_HELPER_ONLY_H
#define STL_HELPER_ONLY_H

#include <iostream>
#include <fstream>
#include <sstream>
#include <algorithm>
#include <vector>

#include <boost/foreach.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/program_options.hpp>

// string
#define str_t std::string
#define str_vec_t std::vector<std::string>

// index vector
#define vi_t std::vector<int>

// containers
#define pb push_back
#define sz(x) ((int)((x).size()))
#define all_element(x) (x).begin(), (x).end()
#define tr(x, it) for ( typeof((x).begin()) it = (x).begin(); it != (x).end(); it++)
#define tr1(x, it) for ( typeof((x).begin1()) it = (x).begin1(); it != (x).end1(); it++)
//#define const_iterator(x) (typeof(x))::const_iterator
//#define const_for_each(x, it) for (const_iterator(x) it = (x).begin(); it != (x).end(); it++) 

// math
#define sqr(x) ((x)*(x))

// Messaging, logging
#define ENDL std::endl
#define MSG(x) { std::cerr << x << ENDL; }
#define MSG_VERBOSE(vm, x) { if (vm.count("verbose")) std::cerr << x << ENDL; }
#define FATAL_ERROR(x) { std::cerr << "line " << __LINE__ << " file " << __FILE__ << " " << x << ENDL; exit(1); }

// file
#define FileAccessWrite(s, f) std::ofstream s; FileAccess::open2write(s, f);
#define FileAccessRead(s, f) std::ifstream s; FileAccess::open2read(s, f);
#define FileAccessAppend(s, f) std::ofstream s; FileAccess::open2append(s, f);
#define FileAccessCreate(f) { std::ofstream s; FileAccess::open2write(s, f); s.close(); }
#define FileAccessLine(s, l); std::string l; std::getline(s, l);
#define FileAccessLineSplit(s, l, t, d) std::string l; std::getline(s, l); std::vector<std::string> t; boost::split(t, l, boost::is_any_of(d), boost::token_compress_on);

class FileAccess
{
 public:
  static void open2read(std::ifstream& input, const std::string& fName);
  static void open2write(std::ofstream& output, const std::string& fName);
  static void open2append(std::ofstream& output, const std::string& fName);  
  static std::string getline(std::ifstream& input);
};

// program options
namespace po = boost::program_options;
#define VM(vm, param, type) (vm[param].as<type>())
#define VMIF(vm, param, type, def_val) ((vm.count(param)) ? VM(vm, param, type) : (def_val))
struct RequiredParameter {
  boost::program_options::variables_map& vm_;
  std::string job_;

  RequiredParameter(boost::program_options::variables_map& vm, 
		  const std::string& job) 
  : vm_(vm), job_(job) {}

  RequiredParameter& operator() (const std::string& param) {
    if (!vm_.count(param)) {
      MSG("job=" << job_ << " needs --" << param);
      exit(1);
    }
    return *this;
  }
};

// string conversion
template <typename T>
T s2(const std::string& s) 
{
  std::stringstream ss(s);
  T v;
  ss >> v;
  return v;
}

template <typename T>
std::string tos(const T& v) {
  std::stringstream ss;
  ss << v;
  return ss.str();
}

// Limit
#define DOUBLE_INFINITY std::numeric_limits<double>::infinity()
#endif
